package com.wolfpire.workflow.spring;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jbpm.api.Execution;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.cmd.Command;
import org.jbpm.pvm.internal.env.EnvironmentFactory;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.id.DbidGenerator;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.model.ProcessDefinitionImpl;
import org.jbpm.pvm.internal.task.TaskImpl;
import org.springframework.stereotype.Service;

import com.wolfpire.workflow.common.Constants;
import com.wolfpire.workflow.em.NodeType;
import com.wolfpire.workflow.em.ProcessStatus;
import com.wolfpire.workflow.om.Forms;
import com.wolfpire.workflow.om.JbpmTask;
import com.wolfpire.workflow.om.Node;
import com.wolfpire.workflow.om.ProInstance;
import com.wolfpire.workflow.utils.JbpmUtil;

@Service
public class JbpmService{
	
	@Resource private ProcessEngine processEngine;
	
	@Resource private ProInstanceService proInstanceService;
	
	@Resource private NodeService nodeService;
	
	@Resource private FormsService formsService;
	
	@Resource private MyTaskService myTaskService;
	

	/**
	 * 根据文件名部署新流程定义
	 * @param repositoryService
	 * @param resourceName
	 * @return 流程定义ID
	 */
	public String deployProcessDefinition(String resourceName)  {
		File file = new File(resourceName);
		return processEngine.getRepositoryService().createDeployment().addResourceFromFile(file).deploy();
	}
	
	public void setExecutionVariable(String executionId, String objName, Object varObj){
		processEngine.getExecutionService().setVariable(executionId, objName, varObj);
	}
	
	public Object getExecutionVariable(String executionId, String objName){
		return processEngine.getExecutionService().getVariable(executionId, objName);
	}
	
	public void setTaskVariables(String taskId, Map<String, String> vmap){
		processEngine.getTaskService().setVariables(taskId, vmap);
	}
	

	/**
	 * 根据流程实例获取流程定义ID
	 * @param ex
	 * @return
	 */
	public Long getDeploymentId(ExecutionImpl ex){
		return (Long) ex.getVariable("deploymentId");
	}
	
	/**
	 * 根据任务ID获取流程定义ID 
	 * @param taskId 任务ID 
	 * @return
	 */
	public Long getDeploymentId(String taskId){
		return (Long) getTask(taskId).getExecution().getVariable("deploymentId");
	}
	
	/** 
	 * 将to XXX 转为 XXX
	 * @param toNodeName
	 * @return
	 */
	public String getNodeName(String toNodeName){
		return toNodeName.substring(3, toNodeName.length());
	}
	
	/**
	 * 获取JBPM流程定义
	 * @param processEngine
	 * @param processDefinitionId
	 * @return
	 */
	public ProcessDefinitionImpl getPdi(String processDefinitionId){
		//arg0).processDefinitionId(
		return (ProcessDefinitionImpl) processEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId(processDefinitionId).uniqueResult();
	}
	

	
	/**根据流程实例获取流程实例
	 * @return
	 */
	public ProcessDefinitionImpl getPdiByEx(ExecutionImpl ex){
		
		return getPdi(String.valueOf(getDeploymentId(ex)));
	}
	
	
	/**
	 * 根据任务获取实例ID
	 * @param task
	 * @return
	 */
	public Long getInstanceIdByTask(TaskImpl task) {
	
		return Long.valueOf(task.getProcessInstance().toString().split("\\.")[1].split("\\]")[0]);
	}
	
	/**
	 * 根据流程实例ID获取流程实例
	 * @param executionId
	 * @return
	 */
	public ExecutionImpl getExecutionImpl(String executionId){
		return (ExecutionImpl) processEngine.getExecutionService().findExecutionById(executionId);
	}
	
	
	public ProcessInstance getProcessInstance(String nameId){
		return processEngine.getExecutionService().findProcessInstanceById(nameId);
	}
	
	
	/**
	 * 启动流程
	 * @param flowName
	 * @param varMap
	 * @return
	 */
	public ExecutionImpl startProInstanceByKey(String flowName, Map<String, Object> varMap){
		return (ExecutionImpl) processEngine.getExecutionService().startProcessInstanceByKey(flowName, varMap);
	}
	
	/**
	 * 根据任务ID获取任务实例
	 * @param taskId
	 * @return
	 */
	public TaskImpl getTask(String taskId){
		if(taskId != null) {
			return (TaskImpl) processEngine.getTaskService().getTask(taskId);
		} 
		return null;
	}
	
	public TaskImpl getTask(String taskId, String instanceId){
		if(!StringUtils.isBlank(taskId)) {
			return (TaskImpl) processEngine.getTaskService().getTask(taskId);
		}
		return getCurTask(instanceId);
	}
	
	/**
	 * 根据流程实例ID获取当前任务
	 * @param instanceId
	 * @return
	 */
	public TaskImpl getCurTask(String instanceId){
//		List<Map<String, Object>> myTaskList = myTaskService.queryMyTaskByInstanceId(Long.parseLong(instanceId));
		List<JbpmTask> jbpmTasks = this.myTaskService.getJbpmTasks(instanceId);
		String taskId = jbpmTasks.get(0).getDbId();
		return getTask(taskId.toString());
	}
	
	public EnvironmentImpl getEnvironmentImpl(){
		return (EnvironmentImpl)((EnvironmentFactory)processEngine).openEnvironment();
	}

	
	/**
	 * 任务办理
	 * @param taskId 任务ID
	 */
	public void completeTask(String taskId){
		processEngine.getTaskService().completeTask(taskId);
	}
	
	/**
	 * 任务办理
	 * @param taskId 任务ID
	 * @param toNodeName 下一环节任务名称，格式to XXX
	 */
	public void completeTask(String taskId, String toNodeName){
		processEngine.getTaskService().completeTask(taskId, toNodeName);
	}
	
	

	/**
	 * 手动结束流程实例
	 * @param nameId
	 */
	public void endProInstance(String nameId, Long instanceId){
		//1、JBPM 结束流程
		processEngine.getExecutionService().endProcessInstance(nameId, Execution.STATE_ENDED);
		//2、流程实例状态改为归档状态
		ProInstance proInstance = proInstanceService.get(instanceId);
		proInstance.setEndTime(new Date());
		proInstance.setStatus(ProcessStatus.COMPLETED.getIndex());
		proInstance.setTimeLimitStatus(Constants.END);
		proInstanceService.save(proInstance);
	}
	
	/**
	 * 获取JBPM序列ID
	 * @param processEngine
	 * @return
	 */
	@SuppressWarnings("static-access")
	public long getNextId(){
		EnvironmentImpl env = ((EnvironmentFactory)processEngine).openEnvironment();
		long dbId = env.getFromCurrent(DbidGenerator.class).getNextId();
		env.close();
		return dbId;
	}
	
	/**
	 * 根据实例ID判断流程是否结束
	 * @param execId
	 * @return
	 */
	public boolean flowIsEnd(String execId, Node nextNode){
		try {
			boolean isEnd = processEngine.getExecutionService().createProcessInstanceQuery()
					.processInstanceId(execId).uniqueResult().isEnded();
			if (isEnd) {
				// 回写
				proInstanceService.endMyProInstance(Long.parseLong(execId));
			}
			return isEnd;
		} catch (NullPointerException e) {
			if (null != nextNode && nextNode.getNodeType().equals(NodeType.END.getIndex())) {
				// 回写
				proInstanceService.endMyProInstance(Long.parseLong(execId));
				return true;
			}
			return false;
		} 
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void execute(Command command){
		processEngine.execute(command);
	}
	
	public String getProFormUrl(Long formTypeId){
		if (formTypeId != null) {
			Forms forms = formsService.get(formTypeId);
			if(StringUtils.isBlank(forms.getHostUrl())){
				return forms.getDetailUrl();
			}else{
				return forms.getHostUrl() + forms.getDetailUrl();
			}
		}
		return null;
	}
	
	
	/**
	 * 获取下一环节（如果是决策环节获取决策节点下一环节）
	 * @param taskName 当前环节名称
	 * @param flowXml 流程图XML
	 * @param deploymentId 流程定义ID
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Node> getNextActivity(String taskName, String flowXml, Long deploymentId){
		
		List<Node> nodes = new ArrayList<Node>();
		
		try {
			Document doc = DocumentHelper.parseText(flowXml);
			Element root = doc.getRootElement();//获取根节点
			/* 解析任务节点 */
			Iterator<Element> nodeIterator = root.elementIterator();
			//root.elementIterator(Qn)
			while(nodeIterator.hasNext()) {
				Element el = (Element)nodeIterator.next(); 
				String nodeName = el.attributeValue("name");
				if(taskName.equals(nodeName)){
					Iterator<Element> tranIterator =  el.elementIterator("transition");
					//<transition name="to 网格人员处理" to="网格人员处理"/>
					while (tranIterator.hasNext()) {
						Element tranEl = (Element)tranIterator.next(); 
						Node node = nodeService.getNode(deploymentId, tranEl.attributeValue("to"));
						nodes.add(node);
					}
				}
			}
		} catch (DocumentException e) {
			e.printStackTrace();
			return null;
		}
		
		return nodes;
	}
	
	/**
	 * 任务办理
	 * @param taskId
	 * @param nextNodeName
	 * @param ex
	 * @param pdi
	 */
	public void complete(String taskId, String nextNodeName, ExecutionImpl ex,
			ProcessDefinitionImpl pdi, boolean freeJumpCheck) {
		if(null != nextNodeName && !freeJumpCheck){
			completeTask(taskId, "to "+nextNodeName);
		}else if(null != nextNodeName && freeJumpCheck){
			String srcName = ex.getActivityName();
			ActivityImpl act = JbpmUtil.addOutTransition(pdi, srcName,nextNodeName);
			ex.setActivity(act);
			processEngine.getExecutionService().signalExecutionById(ex.getId(), "to "+ nextNodeName);
			JbpmUtil.removeOutTransition(pdi, nextNodeName, srcName);
		}else {
			completeTask(taskId);
		}
	}

	
}
